import { PagePollItemtDto, addPollDto } from '../../dto/vote/vote.dto';
import { Poll } from '../../entities/poll.entity';
import { Singer } from '../../entities/singer.entity';
import { VoteRecord } from '../../entities/vote-record.entity';
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Between, In, Like, Repository } from 'typeorm';
import * as moment from 'moment';
@Injectable()
export class PollService {
  constructor(
    @InjectRepository(Poll)
    private voteRepository: Repository<Poll>,

    @InjectRepository(VoteRecord)
    private voteRecordRepository: Repository<VoteRecord>,
    @InjectRepository(Singer)
    private singerRepository: Repository<Singer>,
  ) {}
  /**
   *  根据创建投票
   */
  async create(voteData: Partial<addPollDto>): Promise<Poll> {
    try {
      const { singerIds, ...otherData } = voteData; // 解构出歌手ID列表和其他数据
      const poll = this.voteRepository.create(otherData); // 创建投票项目，排除了歌手ID列表

      if (singerIds && singerIds.length > 0) {
        const singers = await this.singerRepository.find({
          where: { id: In(singerIds) },
        }); // 根据歌手ID列表查询歌手实体
        poll.singers = singers; // 将查询到的歌手与投票项目关联
      }

      return await this.voteRepository.save(poll); // 保存投票项目
    } catch (error) {
      // 处理数据库操作异常

      return error;
    }
  }

  /**
   *  查所有投票
   */
  async findAll(): Promise<Poll[]> {
    try {
      return await this.voteRepository.find({
        relations: ['singers', 'post'],
        order: {
          createdTime: 'DESC',
        },
      });
    } catch (error) {
      // 处理数据库操作异常
      throw new Error('Failed to fetch votes' + error);
    }
  }
  /**
   *  根据查id投票项目
   */
  async findOne(id: string): Promise<Poll> {
    try {
      const vote = await this.voteRepository.findOne({
        where: { id },
        join: {
          alias: 'poll',
          leftJoinAndSelect: {
            singersId: 'poll.singers',
            postId: 'poll.post',
          },
        },
      });
      if (!vote) {
        throw new NotFoundException(`Poll with ID ${id} not found`);
      }
      return vote;
    } catch (error) {
      // 处理数据库操作异常
      return error;
    }
  }
  /**
   * 分页条件用户信息
   */
  async page(param: PagePollItemtDto): Promise<[Partial<Poll>[], number]> {
    const { pageSize, pageNo, id, name, type, published, userId } = param;
    const where: any = {};
    if (id) where.id = id;
    if (name) where.name = Like(`%${name}%`);
    if (type) where.account = Like(`%${type}%`);
    if (published) where.roleIds = Like(`%${published}%`);
    if (userId) where.userId = userId;

    const [voteList, total] = await this.voteRepository.findAndCount({
      where,
      order: {
        createdTime: 'DESC',
      },
      join: {
        alias: 'poll',
        leftJoinAndSelect: {
          singersId: 'poll.singers',
          postId: 'poll.post',
        },
      },
      take: pageSize,
      skip: (pageNo - 1) * pageSize,
    });

    // 将角色信息筛选为所需字段
    const result = voteList.map((vote) => {
      const { singers, post, ...voteList } = vote; // 将投票信息和歌手 文章信息分离

      return { ...voteList, singers };
    });

    return [result, total];
  }

  /**
   * 根据投票 ID 修改投票
   */
  async update(updatedData: Partial<addPollDto>): Promise<Poll> {
    try {
      // 从更新数据中获取投票 ID
      const voteId = updatedData.id;

      if (!voteId) {
        throw new Error('投票 ID 不能为空');
      }

      // 解构出歌手ID列表和其他数据
      const { singerIds, ...otherData } = updatedData;

      // 查询现有的投票项目
      const pollToUpdate = await this.voteRepository.findOne({
        where: { id: voteId },
      });

      if (!pollToUpdate) {
        throw new Error(`找不到 ID 为 ${voteId} 的投票项目`);
      }

      // 如果存在歌手ID列表，则更新投票项目关联的歌手
      if (singerIds && singerIds.length > 0) {
        const singers = await this.singerRepository.find({
          where: { id: In(singerIds) },
        });
        pollToUpdate.singers = singers;
      } else {
        pollToUpdate.singers = []; // 清空关联的歌手列表
      }

      // 更新投票项目的其他属性
      Object.assign(pollToUpdate, otherData);

      // 保存更新后的投票项目
      const updatedPoll = await this.voteRepository.save(pollToUpdate);

      return updatedPoll;
    } catch (error) {
      // 处理数据库操作异常
      throw new Error(`Failed to update vote: ${error.message}`);
    }
  }

  /**
   *  根据查id 删除投票
   */
  async remove(id: string): Promise<void> {
    try {
      // 查询现有的投票项目

      const vote = await this.voteRepository.findOne({
        where: { id },
        relations: ['singers', 'post'],
      });
      vote.singers = [];
      vote.post = null;
      console.log('result', vote);
      if (vote) {
        const result = await this.voteRepository.remove(vote);
        console.log(result, 'result');
      } else {
      }
    } catch (error) {
      // 处理数据库操作异常
      throw new Error(`Failed to delete vote with ID ${id}` + error);
    }
  }
  /**
   *  根据查userId: string, singerId: string投票
   */
  async vote(userId: string, singerId: string): Promise<any> {
    // 检查用户是否已经投过票
    const currentTime = moment().format('YYYY-MM-DD HH:mm:ss');

    // 检查用户今天是否已经投过票
    const existingVoteToday = await this.voteRecordRepository.findOne({
      where: {
        userId,
        createdTime: Between(
          moment().startOf('day').format('YYYY-MM-DD HH:mm:ss'),
          moment().endOf('day').format('YYYY-MM-DD HH:mm:ss'),
        ),
      },
    });
    if (existingVoteToday) {
      return '今天已经投过票';
    }

    // 创建投票记录
    const voteRecord = this.voteRecordRepository.create({
      userId,
      singerId,
    });
    await this.voteRecordRepository.save(voteRecord);

    // 更新歌手的投票数量
    const singer = await this.singerRepository.findOne({
      where: { id: singerId },
    });
    singer.votedCount += 1;
    await this.singerRepository.save(singer);
    // 更新投票项目的数量
    const poll = await this.voteRepository.findOne({
      where: { singers: { id: singerId } }, // 根据歌手ID查询相关的投票项目
      relations: ['singers'], // 加载与投票项目相关的所有歌手
    });
    if (poll) {
      // 计算所有歌手的总票数
      const totalVotes = poll.singers.reduce(
        (total, singer) => total + singer.votedCount,
        0,
      );
      poll.count = totalVotes;
      await this.voteRepository.save(poll);
    }
    return '投票成功';
  }

  /**
   *
   * @returns  歌手排行榜
   */
  async getSingerRanking(pollId): Promise<any[]> {
    try {
      const singerRanking = await this.singerRepository
        .createQueryBuilder('singer')
        .leftJoin('singer.voteRecords', 'voteRecord') // 使用 voteRecords 替代 votes
        .select([
          'singer.id AS singerId',
          'singer.name AS singerName',
          'singer.musicUrl AS musicUrl',
          'COUNT(voteRecord.id) AS voteCount', // 使用 voteRecord 替代 votes
        ])
        .where('singer.pollId = :pollId', { pollId })
        .groupBy('singer.id, singer.name')
        .orderBy('COUNT(voteRecord.id)', 'DESC')
        .getRawMany();

      return singerRanking;
    } catch (error) {
      // 处理数据库操作异常
      console.error('Failed to fetch singer ranking:', error);
      throw new Error('Failed to fetch singer ranking');
    }
  }

  /**
   * 音乐排行榜
   */

  async getMusicRanking(pollId): Promise<any[]> {
    try {
      const musicRanking = await this.voteRecordRepository
        .createQueryBuilder('voteRecord')
        .leftJoinAndSelect('voteRecord.singer', 'singer')
        .select([
          'singer.id',
          'singer.musicName AS musicName',
          'singer.musicUrl AS musicUrl',
          'COUNT(voteRecord.id) AS voteCount',
        ])
        .where('singer.pollId = :pollId', { pollId })
        .groupBy('singer.id')
        .orderBy('COUNT(voteRecord.id)', 'DESC')
        .getRawMany();

      return musicRanking;
    } catch (error) {
      // 处理数据库操作异常
      throw new Error('Failed to fetch music ranking');
    }
  }

  /**
   * 统计投票的时间趋势，包括日、周和月的投票数量
   * 这个方法会查询数据库，按照时间单位对投票进行分组，并返回每个时间段内的投票数量。
   * @param timeUnit 投票时间趋势统计
   * @returns 每个时间段内的投票数量
   */
  async getVoteTrendByTimeUnit(
    timeUnit: 'day' | 'week' | 'month',
  ): Promise<any> {
    try {
      let now = moment().utcOffset(8); // 设置时区为中国时区
      let startDate;
      let endDate;
      switch (timeUnit) {
        case 'day':
          startDate = now.clone().startOf('day');
          endDate = now.clone().endOf('day');
          // 每天每小时的投票统计
          const dailyHourlyTrend = await this.getDailyHourlyTrend(
            startDate,
            endDate,
          );
          return dailyHourlyTrend;
          break;
        case 'week':
          startDate = now.clone().startOf('isoWeek');
          endDate = now.clone().endOf('isoWeek');
          // 每周的投票统计
          const weeklyTrend = await this.getWeeklyTrend(startDate, endDate);
          return weeklyTrend;
          break;
        case 'month':
          startDate = now.clone().startOf('month').startOf('day');
          endDate = now.clone().endOf('month').endOf('day');

          // 每月的投票统计
          const monthlyTrend = await this.getMonthlyTrend(startDate, endDate);

          return monthlyTrend;
          break;
        default:
          startDate = now.clone().startOf('day');
          endDate = now.clone().endOf('day');
          return dailyHourlyTrend;
      }
    } catch (error) {
      // 处理数据库操作异常
      throw new Error(`${timeUnit} ` + error);
    }
  }

  async getDailyHourlyTrend(
    startDate: moment.Moment,
    endDate: moment.Moment,
  ): Promise<any> {
    const dailyHourlyTrend = [];

    for (let i = 0; i < 24; i++) {
      // 查询每小时的投票数量
      const voteCount = await this.getVoteCountByHour(startDate, i);
      const formattedDate = `${moment(startDate)
        .startOf('day')
        .add(i, 'hours')
        .format('HH:00')}`;
      dailyHourlyTrend.push({ date: formattedDate, voteCount });
    }

    return dailyHourlyTrend;
  }

  async getVoteCountByHour(date: moment.Moment, hour: number): Promise<number> {
    const startHour = date.clone().startOf('day').add(hour, 'hours');
    const endHour = date
      .clone()
      .startOf('day')
      .add(hour, 'hours')
      .endOf('hour');

    const voteCountResult = await this.voteRecordRepository
      .createQueryBuilder('voteRecord')
      .select('COUNT(voteRecord.id) AS voteCount')
      .where(
        'voteRecord.createdTime >= :startHour AND voteRecord.createdTime <= :endHour',
        { startHour: startHour.toDate(), endHour: endHour.toDate() },
      )
      .getRawOne();

    return parseInt(voteCountResult.voteCount) || 0;
  }

  async getWeeklyTrend(
    startDate: moment.Moment,
    endDate: moment.Moment,
  ): Promise<any[]> {
    const weeklyTrend = [];

    // 遍历该周的每一天
    for (let i = 0; i < 7; i++) {
      const currentDate = startDate.clone().add(i, 'days');
      const voteCount = await this.getVoteCountByDate(currentDate);
      weeklyTrend.push({ date: currentDate.format('YYYY-MM-DD'), voteCount });
    }

    return weeklyTrend;
  }
  async getVoteCountByDate(date: moment.Moment): Promise<number> {
    const startOfDay = date.clone().startOf('day');
    const endOfDay = date.clone().endOf('day');

    const voteCountResult = await this.voteRecordRepository
      .createQueryBuilder('voteRecord')
      .select('COUNT(voteRecord.id) AS voteCount')
      .where(
        'voteRecord.createdTime >= :startOfDay AND voteRecord.createdTime <= :endOfDay',
        { startOfDay: startOfDay.toDate(), endOfDay: endOfDay.toDate() },
      )
      .getRawOne();

    return parseInt(voteCountResult.voteCount) || 0;
  }
  async getMonthlyTrend(
    startDate: moment.Moment,
    endDate: moment.Moment,
  ): Promise<any[]> {
    const monthlyTrend = [];
    const startYear = startDate.clone().startOf('year');
    const endYear = endDate.clone().endOf('year');

    // 从1月开始遍历到12月
    for (let month = 1; month <= 12; month++) {
      const currentMonth = startYear.clone().month(month - 1);
      const voteCount = await this.getVoteCountByRange(currentMonth, 'month');
      monthlyTrend.push({ date: currentMonth.format('YYYY-MM'), voteCount });
    }

    return monthlyTrend;
  }

  async getVoteCountByRange(
    date: moment.Moment,
    range: string,
  ): Promise<number> {
    let startOfRange, endOfRange;

    if (range === 'month') {
      startOfRange = date.clone().startOf('month');
      endOfRange = date.clone().endOf('month');
    }

    const voteCountResult = await this.voteRecordRepository
      .createQueryBuilder('voteRecord')
      .select('COUNT(voteRecord.id) AS voteCount')
      .where(
        `voteRecord.createdTime >= :startOfRange AND voteRecord.createdTime <= :endOfRange`,
        {
          startOfRange: startOfRange.toDate(),
          endOfRange: endOfRange.toDate(),
        },
      )
      .getRawOne();

    // 如果结果为空，则返回0
    return parseInt(voteCountResult?.voteCount) || 0;
  }
}
